package com.rtsapp.version.builder.utils;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.rtsapp.version.builder.tool.VersionTool;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Zip;
import org.apache.tools.ant.types.FileSet;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class FileUtils {


    public static String getMd5(FileInputStream inputStream, long length) throws IOException {
        MappedByteBuffer buffer = inputStream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, length);
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(buffer);

        byte temp[] = md5.digest();
        char str[] = new char[16 * 2];
        int k = 0;
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

        for (int i = 0; i < 16; i++) {
            byte byte0 = temp[i];

            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
            str[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(str);
    }

    public static final void scannerAllFiles(File dir, List<File> files, Set<String> ignoreName) {
        File[] fs = dir.listFiles();
        if (fs != null) {
            for (int i = 0; i < fs.length; i++) {
                if (ignoreName.contains(fs[i].getName())) {
                    continue;
                }
                if (fs[i].isDirectory()) {
                    scannerAllFiles(fs[i], files, ignoreName);
                } else {
                    files.add(fs[i]);
                }
            }
        }
    }

    /**
     * 复制单个文件
     *
     * @param fromFile 原文件
     * @param newFile  复制后路径
     * @return boolean
     */
    public static void copyFile(File fromFile, File newFile) {
        try (InputStream input = new FileInputStream(fromFile);
             FileOutputStream output = new FileOutputStream(newFile)) {
            byte[] buffer = new byte[4096];
            int len;
            while ((len = input.read(buffer)) != -1) {
                output.write(buffer, 0, len);
            }
            output.flush();
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    /**
     * 新建目录
     *
     * @param folderPath
     * @return boolean
     */
    public static void newFolder(String folderPath) {
        try {
            String filePath = folderPath;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            if (!myFilePath.exists()) {
                myFilePath.mkdirs();
            }
        } catch (Exception e) {
            System.out.println("新建目录操作出错");
            e.printStackTrace();
        }
    }

    /***
     * zip压缩一个目录
     *
     * @param srcPathName 源
     * @param pathName    目标zip文件
     */
    public static void zipCompression(String srcPathName, String pathName) {
        File zipFile = new File(pathName);
        File srcdir = new File(srcPathName);
        if (!srcdir.exists())
            throw new RuntimeException(srcPathName + "不存在！");

        Project prj = new Project();
        Zip zip = new Zip();
        zip.setProject(prj);
        zip.setDestFile(zipFile);
        FileSet fileSet = new FileSet();
        fileSet.setProject(prj);
        fileSet.setDir(srcdir);
        //fileSet.setIncludes("**/*.java"); 包括哪些文件或文件夹 eg:zip.setIncludes("*.java");
        //fileSet.setExcludes(...); 排除哪些文件或文件夹
        zip.addFileset(fileSet);

        zip.execute();

    }

    /**
     * 删除文件
     *
     * @param filePathAndName String 文件路径及名称
     * @return boolean
     */
    public static void delFile(String filePathAndName) {
        try {
            String filePath = filePathAndName;
            filePath = filePath.toString();
            File myDelFile = new File(filePath);
            myDelFile.delete();

        } catch (Exception e) {
            System.out.println("删除文件操作出错");
            e.printStackTrace();

        }

    }

    /**
     * 删除文件夹
     *
     * @param folderPath String
     * @return boolean
     */
    public static void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); // 删除完里面所有内容
            String filePath = folderPath;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            myFilePath.delete(); // 删除空文件夹

        } catch (Exception e) {
            System.out.println("删除文件夹操作出错");
            e.printStackTrace();

        }

    }


    /**
     * 删除文件夹里面的所有文件
     *
     * @param path String 文件夹路径
     */
    public static void delAllFile(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return;
        }
        if (!file.isDirectory()) {
            return;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
                delFolder(path + "/" + tempList[i]);// 再删除空文件夹
            }
        }
    }

    /**
     * 拆分文件
     *
     * @param fileName 待拆分的完整文件名
     * @param byteSize 按多少字节大小拆分
     * @return 拆分后的文件名列表
     * @throws IOException
     */
    public static List<String> splitBySize(String path, String fileName, int byteSize, JsonArray fileArray) throws IOException {
        List<String> parts = new ArrayList<>();
        File file = new File(fileName);
        int count = (int) Math.ceil(file.length() / (double) byteSize);

//        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(count, count * 3, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(count * 2));
//
//        for (int i = 0; i < count; i++) {
//            threadPool.execute(new PutFileRunnable(byteSize, i * byteSize, path + file.getName() + "." + String.format("%0" + String.valueOf(count - 1).length() + "d", i) + ".part", file));
//            parts.add(file.getPath().replace("\\", "/") + "." + String.format("%0" + String.valueOf(count - 1).length() + "d", i) + ".part");
//        }

        for (int i = 0; i < count; i++) {
            RandomAccessFile rFile;
            OutputStream os = null;
            String md5 = null;
            FileInputStream inputStream = null;
            try {
                rFile = new RandomAccessFile(file, "r");
                byte[] b = new byte[byteSize];
                rFile.seek(i * byteSize);// 移动指针到每“段”开头
                int s = rFile.read(b);
                String partFileName = path + file.getName() + "." + String.format("%0" + String.valueOf(count - 1).length() + "d", i) + ".part";
                os = new FileOutputStream(partFileName);
                os.write(b, 0, s);
                os.flush();
                System.out.println("切割成功: " + partFileName);
                File targetFile = new File(partFileName);
                inputStream = new FileInputStream(targetFile);
                md5 = FileUtils.getMd5(inputStream, targetFile.length());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                os.close();
                inputStream.close();
            }

            JsonObject fileItem = new JsonObject();
            fileArray.add(fileItem);
            String filePath = file.getPath().replace("\\", "/") + "." + String.format("%0" + String.valueOf(count - 1).length() + "d", i) + ".part";
            fileItem.addProperty("md5", md5);

            parts.add(filePath);
        }

        return parts;
    }

    /**
     * 复制整个文件夹内容
     *
     * @param oldPath String 原文件路径
     * @param newPath String 复制后路径
     * @return boolean
     */
    public static void copyFolder(String oldPath, String newPath) {

        try {
            (new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹
            File a = new File(oldPath);
            String[] file = a.list();
            File temp = null;
            for (int i = 0; i < file.length; i++) {
                if (oldPath.endsWith(File.separator)) {
                    temp = new File(oldPath + file[i]);
                } else {
                    temp = new File(oldPath + File.separator + file[i]);
                }

                if (temp.isFile()) {
                    FileInputStream input = new FileInputStream(temp);
                    FileOutputStream output = new FileOutputStream(newPath
                            + "/" + (temp.getName()).toString());
                    byte[] buffer = new byte[1024 * 5];
                    int len;
                    while ((len = input.read(buffer)) != -1) {
                        output.write(buffer, 0, len);
                    }
                    output.flush();
                    output.close();
                    input.close();
                }
                if (temp.isDirectory()) {// 如果是子文件夹
                    copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);
                }
            }
        } catch (Exception e) {
            System.out.println("复制整个文件夹内容操作出错");
            e.printStackTrace();

        }

    }
//    /**
//     * 新建目录
//     *
//     * @param folderPath
//     * @return boolean
//     */
//    public static void newFolder(String folderPath) {
//        try {
//            String filePath = folderPath;
//            filePath = filePath.toString();
//            File myFilePath = new File(filePath);
//            if (!myFilePath.exists()) {
//                myFilePath.mkdir();
//            }
//        } catch (Exception e) {
//            System.out.println("新建目录操作出错");
//            e.printStackTrace();
//        }
//    }
//
//    /**
//     * 新建文件
//     *
//     * @param filePathAndName String 文件路径及名称
//     * @param fileContent     String 文件内容
//     * @return boolean
//     */
//    public static void newFile(String filePathAndName, String fileContent) {
//
//        try {
//            String filePath = filePathAndName;
//            filePath = filePath.toString();
//            File myFilePath = new File(filePath);
//            if (!myFilePath.exists()) {
//                myFilePath.createNewFile();
//            }
//            FileWriter resultFile = new FileWriter(myFilePath);
//            PrintWriter myFile = new PrintWriter(resultFile);
//            String strContent = fileContent;
//            myFile.println(strContent);
//            resultFile.close();
//
//        } catch (Exception e) {
//            System.out.println("新建目录操作出错");
//            e.printStackTrace();
//
//        }
//
//    }
//

    public static class PutFileRunnable implements Runnable {

        public final static int maxRetryTimes = 10;

        String cdnType;
        String keyPrefix;
        String pathPrefix;
        String filePath;
        VersionTool.Times times;
        ConsoleProgressBar cpb;

        public PutFileRunnable(String cdnType, String keyPrefix, String pathPrefix, String filePath, VersionTool.Times times, ConsoleProgressBar cpb) {
            this.cdnType = cdnType;
            this.keyPrefix = keyPrefix;
            this.pathPrefix = pathPrefix;
            this.filePath = filePath;
            this.times = times;
            this.cpb = cpb;
        }

        public void run() {
            boolean b = false;

            times.times.incrementAndGet();

            RuntimeException ex = null;

            IPutFile putFile = null;

            switch (cdnType) {
                case "ufile":
                    putFile = new UFilePutUtil();
                    break;
                case "ks3":
                    putFile = new KS3PutUtil();
                    break;
                case "s3":
                    putFile = new S3PutUtil();
                    break;
                case "ftp":
                    putFile = new FtpPutUtil();
                    break;
                case "copy":
                    putFile = new CopyPutUtil();
                    break;
                default:
                    System.out.println("无需上传");
                    break;
            }
            if (putFile != null) {
                for (int j = 0; j < maxRetryTimes; j++) {
                    try {
                        b = putFile.putFiles(keyPrefix, pathPrefix, filePath);
                        ex = null;
                        break;
                    } catch (RuntimeException e) {
                        System.out.println("远程服务器无响应, 尝试进行第 " + (j + 1) + " 次重试: ");
                        cpb.show("重新上传" + pathPrefix + filePath, times.times.get());
                        ex = e;
                    }
                }
            }
            if (ex != null) {
                ex.printStackTrace();
                System.exit(1);
                throw ex;
            }
            if (b) {
                cpb.show("上传完成: " + pathPrefix + filePath, times.times.get());
            } else {
                cpb.show("跳过文件: " + pathPrefix + filePath, times.times.get());
            }
        }
    }
//
//    /**
//     * 移动文件到指定目录
//     *
//     * @param oldPath
//     * @param newPath
//     */
//    public static void moveFile(String oldPath, String newPath) {
//        copyFile(new File(oldPath), new File(newPath));
//        delFile(oldPath);
//
//    }
//
//    /**
//     * 移动文件到指定目录
//     *
//     * @param oldPath
//     * @param newPath
//     */
//    public static void moveFolder(String oldPath, String newPath) {
//        copyFolder(oldPath, newPath);
//        delFolder(oldPath);
//
//    }
//
//    /**
//     * 获取文件扩展名
//     *
//     * @param file
//     * @return
//     */
//    public static String getFileExtension(File file) {
//        String fileName = file.getName();
//        if (fileName.indexOf(".") != -1) {
//            return fileName.substring(fileName.indexOf(".") + 1);
//        } else {
//            return "";
//        }
//    }
//


//    public static final void fileOutput(byte[] bytes, String path) {
//        File file = new File(path);
//        try (FileOutputStream fop = new FileOutputStream(file)) {
//            if (!file.exists()) {
//                file.createNewFile();
//            }
//            fop.write(bytes);
//            fop.flush();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
//
//    public static final byte[] fileInput(String path) {
//        byte[] bytes = null;
//        File file = new File(path);
//        if (!file.exists()) {
//            return null;
//        }
//        long fileSize = file.length();
//        if (fileSize > Integer.MAX_VALUE) {
//            System.out.println("file too big...");
//            return null;
//        }
//        try (FileInputStream fi = new FileInputStream(file)) {
//            bytes = new byte[(int) fileSize];
//            int offset = 0;
//            int numRead;
//            while (offset < bytes.length && (numRead = fi.read(bytes, offset, bytes.length - offset)) >= 0) {
//                offset += numRead;
//            }
//            // 确保所有数据均被读取
//            if (offset != bytes.length) {
//                throw new IOException("Could not completely read file " + file.getName());
//            }
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return bytes;
//    }

}
